////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include "TextureHullHandler.hpp"

#include <SmegLight/Hull/TextureHull.hpp>

#include <SmegLight/Light/LightSystem.hpp>

#include "../../tinyxml2/tinyxml2.h"
#include "../../Canvas/SmegEditorCanvas.hpp"

////////////////////////////////////////////////////////////
/// Construct the TextureHullHandler
////////////////////////////////////////////////////////////
TextureHullHandler::TextureHullHandler() :
    QuadTreeOccupantHandler(),
    m_CurrentTextureFilename( wxEmptyString )
{
}

////////////////////////////////////////////////////////////
/// Copy Constructor of the TextureHullHandler
////////////////////////////////////////////////////////////
TextureHullHandler::TextureHullHandler( const TextureHullHandler& _Copy ) :
    QuadTreeOccupantHandler( _Copy ),
    m_CurrentTextureFilename( _Copy.m_CurrentTextureFilename )
{
}

////////////////////////////////////////////////////////////
/// Init the handler and setup the properties
/// QuadTreeOccupantHandler::InitFromGrid need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool TextureHullHandler::InitFromGrid( wxPropertyGrid* _pPropertyGrid ) {
    bool creationSucess = false;

    // Angle will be set in BaseObjectHandler::Init, that is why we need to call it at the END
    m_pObject = new smeg::light::TextureHull();

    smeg::light::TextureHull* texHull = static_cast< smeg::light::TextureHull* >( m_pObject );

    if ( QuadTreeOccupantHandler::InitFromGrid( _pPropertyGrid ) ) {
        // TEXTURE : Load from a file
        wxString filename = m_CurrentTextureFilename.GetFullPath();
        m_CurrentTextureFilename = wxEmptyString;

        if ( wxEmptyString == filename ) {
            wxFileDialog* fileTexDlg = new wxFileDialog( m_pCanvas->GetParent(),
                                            _T("Load an image..."),
                                            wxEmptyString,
                                            wxEmptyString,
                                            "Images Files (*.png;*.bmp;*.jpg)|*.png;*.bmp;*.jpg",
                                            wxFD_OPEN | wxFD_FILE_MUST_EXIST );
            if ( wxID_CANCEL != fileTexDlg->ShowModal() ) {
                filename = fileTexDlg->GetPath(); 
            }
            fileTexDlg->Destroy();
        }

        if ( wxEmptyString != filename && texHull->SetTexture( filename )) {
            m_CurrentTextureFilename = filename; 
            creationSucess = true;
        }

        if ( creationSucess ) {
            // Repeated
            wxPGProperty* pCurProp = _pPropertyGrid->GetProperty("Repeated");
            wxAny repeatedValue = pCurProp->GetValue();
            texHull->SetRepeated( repeatedValue.As<bool>() );

            // Smooth
            pCurProp = _pPropertyGrid->GetProperty("Smooth");
            wxAny smoothValue = pCurProp->GetValue();
            texHull->SetSmooth( repeatedValue.As<bool>() );
        }
    }

    if ( !creationSucess ) {
        smeg::light::LightSystem::GetInstance()->RemoveHull( texHull );
        m_pObject = NULL;
    }

    return creationSucess;
}
    
////////////////////////////////////////////////////////////
/// Init the handler from an XMLElement
/// QuadTreeOccupantHandler::InitFromXML need to be called AFTER the specialized class
////////////////////////////////////////////////////////////
bool TextureHullHandler::InitFromXML( tinyxml2::XMLElement* _pElement, const wxString& _ProjectPath ) {
    bool successInit = true;
    
    // Get the infos
    tinyxml2::XMLElement* paramElem = _pElement->FirstChildElement( "Param" );

    m_pObject = new smeg::light::TextureHull();
    smeg::light::TextureHull* texHullObj = static_cast< smeg::light::TextureHull* >( m_pObject );

    if ( QuadTreeOccupantHandler::InitFromXML( _pElement, _ProjectPath ) ) {
        while ( paramElem ) {
            wxString paramName = paramElem->Attribute( "name" );

            if ( "Image" == paramName ) {
                m_CurrentTextureFilename = wxFileName( _ProjectPath + wxFileName::GetPathSeparator() + paramElem->Attribute( "value" ) );
                m_CurrentTextureFilename.Normalize();

                if ( !texHullObj->SetTexture( m_CurrentTextureFilename.GetFullPath() ) ) {
                    successInit = false;
                }
            } else if ( "Repeated" == paramName ) {
                texHullObj->SetRepeated( paramElem->BoolAttribute( "value" ) );
            } else if ( "Smooth" == paramName ) {
                texHullObj->SetSmooth( paramElem->BoolAttribute( "value" ) );
            } else if ( "Size" == paramName ) {
                texHullObj->SetSize( sf::Vector2f( paramElem->FloatAttribute( "x" ), paramElem->FloatAttribute( "y" ) ) );
            }

            paramElem = paramElem->NextSiblingElement( "Param" );
        }
    } else {
        smeg::light::LightSystem::GetInstance()->RemoveHull( texHullObj );
        m_pObject = NULL;
        return false;
    }

    return true;
}
    
////////////////////////////////////////////////////////////
/// Add the created object to the scene
////////////////////////////////////////////////////////////
void TextureHullHandler::AddObjectToScene() {
    smeg::light::LightSystem::GetInstance()->AddHull( static_cast< smeg::light::TextureHull* >( m_pObject ) );
}
    
////////////////////////////////////////////////////////////
/// Remove the created object from the scene
////////////////////////////////////////////////////////////
void TextureHullHandler::RemoveObjectFromScene( bool _bDeleteObject ) {
    smeg::light::LightSystem::GetInstance()->RemoveHull( static_cast< smeg::light::TextureHull* >( m_pObject ), _bDeleteObject );
    if ( _bDeleteObject ) {
        m_pObject = NULL;
    }
}
    
////////////////////////////////////////////////////////////
/// Return the value of a property
////////////////////////////////////////////////////////////
wxString TextureHullHandler::GetValueAsString( const wxString& _PropertyName ) const {
    smeg::light::TextureHull * texHullObj = static_cast< smeg::light::TextureHull* >( m_pObject );

    if ( "Repeated" == _PropertyName ) {
        return ( texHullObj->IsRepeated() ? "true" : "false" );
    } else if ( "Smooth" == _PropertyName ) {
        return ( texHullObj->IsSmooth() ? "true" : "false" );
    } else if ( "Size.x" == _PropertyName ) {
        return wxString::Format( "%f",  texHullObj->GetSize().x );
    } else if ( "Size.y" == _PropertyName ) {
        return wxString::Format( "%f",  texHullObj->GetSize().y );
    } else {
        return QuadTreeOccupantHandler::GetValueAsString( _PropertyName );
    }
}
    
////////////////////////////////////////////////////////////
/// Handle the change of a property and apply it to the object
////////////////////////////////////////////////////////////
bool TextureHullHandler::OnPropertyChanged( wxPropertyGrid* _pPropertyGrid, wxPGProperty* _pChangedProperty ) {
    if ( QuadTreeOccupantHandler::OnPropertyChanged( _pPropertyGrid, _pChangedProperty ) ) {
        return true;
    }

    smeg::light::TextureHull * texHullObj = static_cast< smeg::light::TextureHull* >( m_pObject );
    
    // Handle changes in values, as needed
    const wxString& propName(_pChangedProperty->GetName());
    if ( "Image" == propName ) {
        wxString fileName = _pChangedProperty->GetValue().GetString();
        if ( texHullObj->SetTexture( fileName ) ) {
            m_CurrentTextureFilename = fileName; 
        } else {
	        wxMessageBox(_T("Fail To load texture!\n"),
	                        _T("Image loading Error"),
	                        wxOK | wxICON_ERROR,
                            m_pCanvas->GetParent());
            _pChangedProperty->SetValueFromString( wxEmptyString );
            m_CurrentTextureFilename = wxEmptyString; 
        }
    } else if ( "Repeated" == propName ) {
        wxAny repeatedValue = _pChangedProperty->GetValue();
        texHullObj->SetRepeated( repeatedValue.As<bool>() );
    } else if ( "Smooth" == propName ) {
        wxAny smoothValue = _pChangedProperty->GetValue();
        texHullObj->SetSmooth( smoothValue.As<bool>() );
    } else if ( "Size" == propName || "Size" == propName.BeforeFirst( '.' ) ) {
        _pChangedProperty = _pPropertyGrid->GetProperty( "Size" );
        texHullObj->SetSize( sf::Vector2f(
            _pChangedProperty->GetPropertyByName("x")->GetValue().GetAny().As<float>(),
            _pChangedProperty->GetPropertyByName("y")->GetValue().GetAny().As<float>()
            ) );
    } else {
        return false;
    }

    return true;
}
    
////////////////////////////////////////////////////////////
/// Set the texture
////////////////////////////////////////////////////////////
bool TextureHullHandler::SetTexture( const wxString& _textureFilename ) {
    if ( m_pObject && !static_cast< smeg::light::TextureHull* >( m_pObject )->SetTexture( _textureFilename ) ) {
        return false;
    }

    m_CurrentTextureFilename = _textureFilename;

    return false;
}
   
////////////////////////////////////////////////////////////
/// Create an XML string with the value of the object
////////////////////////////////////////////////////////////
wxString TextureHullHandler::InnerXMLString( const wxString& _ProjectPath, const wxString& _Tab ) const {
    smeg::light::TextureHull * texHullObj = static_cast< smeg::light::TextureHull* >( m_pObject );
    wxFileName tmpTextureRelative( m_CurrentTextureFilename );
    tmpTextureRelative.MakeRelativeTo( _ProjectPath );

    return QuadTreeOccupantHandler::InnerXMLString( _ProjectPath, _Tab ) +
        _Tab + wxT( "<Param name=\"Image\" value=\"" ) + tmpTextureRelative.GetFullPath() + wxT( "\" />\n" ) +
        _Tab + wxT( "<Param name=\"Repeated\" value=\"" ) + (texHullObj->IsRepeated() ? wxT( "true" ) : wxT( "false" ) ) + wxT( "\" />\n" ) + 
        _Tab + wxT( "<Param name=\"Smooth\" value=\"" ) + (texHullObj->IsSmooth() ? wxT( "true" ) : wxT( "false" ) ) + wxT( "\" />\n" ) +
        _Tab + wxT( "<Param name=\"Size\" x=\"" ) + wxString::Format( "%f",  texHullObj->GetSize().x ) + 
                                        wxT( "\" y=\"" ) + wxString::Format( "%f",  texHullObj->GetSize().y ) + 
                                        wxT( "\" />\n" );
}